package vg.services.log_manager.realization;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import vg.services.log_manager.interfaces.ILogger;

/**
 * This class realizes interface ILogger.
 * Messages logs to file.
 *
 * @author Timur Zolotuhin (e-mail: tzolotuhin@gmail.com)
 */
public class FileLogger implements ILogger {
	// Main data
    private DataOutputStream output;
	private String fileName = "";

    private final ConsoleLogger consoleLogger;

    private boolean enableDebugMode;

    // Mutex
    private final Object generalMutex = new Object();

    /**
     * Constructor.
     */
    public FileLogger() throws Exception {
		this.consoleLogger = new ConsoleLogger();

		// create log directory, if it isn't exist
        File dir = new File("log");
		if(!dir.exists() || (dir.isFile() && !dir.isDirectory())) {
			try {
				if (dir.mkdir()) {
                    throw new Exception("Couldn't to create log directory " + dir.getAbsolutePath());
                }
			} catch (Exception ex) {
				throw(ex);
			}
		}

        // create file name
        Date data = new Date();
		long time = data.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("dd.M.yyyy H.mm.ss");
		String timeS = sdf.format(time);
        fileName = dir.getAbsolutePath() + File.separatorChar + timeS + "_log.txt";

        // try open file for writing
        try {
            FileOutputStream fos = new FileOutputStream(fileName);
			this.output = new DataOutputStream(fos);
		} catch (IOException ex) {
			throw(new Exception("Couldn't to create file " + fileName));
		}
	}

    @Override
    public void enableDebugMessage(boolean enable) {
        synchronized (generalMutex) {
            enableDebugMode = enable;

            consoleLogger.enableDebugMessage(enable);
        }
    }

    @Override
    public void printErrorAndThrowRuntimeException(String message) throws RuntimeException {
        synchronized (generalMutex) {
            printError(message);
            throw new RuntimeException(message);
        }
    }

    @Override
	public void printDebug(String message) {
        synchronized (generalMutex) {
            if (!enableDebugMode)
                return;

            try {
                // print to console
                this.consoleLogger.printDebug(message);

                // print to file
                this.output.write(("[DEBUG] : " + message + "\n").getBytes());
                this.output.flush();
            } catch (IOException ex) {
                this.consoleLogger.printDebug(message);
            }
        }
	}

    @Override
    public void printError(String message) {
        synchronized (generalMutex) {
            try {
                // print to console
                this.consoleLogger.printError(message);

                // print to file
                this.output.write(("[ERROR] : " + message + "\n").getBytes());
                this.output.flush();
            } catch (IOException ex) {
                this.consoleLogger.printError(message);
            }
        }
	}

    @Override
    public void printInfo(String message) {
        synchronized (generalMutex) {
            try {
                // print to console
                this.consoleLogger.printInfo(message);

                // print to file
                this.output.write(("[INFO] : " + message + "\n").getBytes());
                this.output.flush();
            } catch (IOException ex) {
                this.consoleLogger.printInfo(message);
            }
        }
	}

    @Override
    public void printStackTrace(StackTraceElement[] trace) {
        synchronized (generalMutex) {
            if (trace == null)
                return;
            try {
                this.output.write("[TRACE START]\n".getBytes());
                System.err.print("[TRACE START]\n");
                for (StackTraceElement element : trace) {
                    this.output.write(("[TRACE] : " + element.toString() + "\n").getBytes());
                    System.err.print("[TRACE] : " + element.toString() + "\n");
                }
                this.output.write("[TRACE END]\n".getBytes());
                System.err.print("[TRACE END]\n");
            } catch (IOException e) {
                this.consoleLogger.printStackTrace(trace);
            }
        }
	}

    @Override
    public void printException(Throwable ex) {
        synchronized (generalMutex) {
            if (ex == null)
                return;
            try {
                this.output.write(("[TRACE START] [" + ex.getMessage() + "]\n").getBytes());
                System.err.print(("[TRACE START] [" + ex.getMessage() + "]\n"));
                for (StackTraceElement element : ex.getStackTrace()) {
                    this.output.write(("[TRACE] : " + element.toString() + "\n").getBytes());
                    System.err.print("[TRACE] : " + element.toString() + "\n");
                }
                this.output.write("[TRACE END]\n".getBytes());
                System.err.print("[TRACE END]\n");
            } catch (IOException e) {
                this.consoleLogger.printException(ex);
            }
        }
	}

    @Override
    public String getLoggerInfo() {
        synchronized (generalMutex) {
            return "This logger uses next file " + this.fileName;
        }
	}
}
